/*      */ package com.zimbra.cs.mime;
/*      */ 
/*      */ import com.google.common.annotations.VisibleForTesting;
/*      */ import com.google.common.base.Strings;
/*      */ import com.google.common.collect.ImmutableSet;
/*      */ import com.google.common.collect.Sets;
/*      */ import com.zimbra.common.calendar.ZCalendar.ICalTok;
/*      */ import com.zimbra.common.calendar.ZCalendar.ZCalendarBuilder;
/*      */ import com.zimbra.common.calendar.ZCalendar.ZVCalendar;
/*      */ import com.zimbra.common.localconfig.DebugConfig;
/*      */ import com.zimbra.common.localconfig.KnownKey;
/*      */ import com.zimbra.common.localconfig.LC;
/*      */ import com.zimbra.common.mime.ContentType;
/*      */ import com.zimbra.common.mime.shim.JavaMailInternetAddress;
/*      */ import com.zimbra.common.service.ServiceException;
/*      */ import com.zimbra.common.util.ByteUtil;
/*      */ import com.zimbra.common.util.EmailUtil;
/*      */ import com.zimbra.common.util.FileUtil;
/*      */ import com.zimbra.common.util.L10nUtil;
/*      */ import com.zimbra.common.util.L10nUtil.MsgKey;
/*      */ import com.zimbra.common.util.Log;
/*      */ import com.zimbra.common.util.LogFactory;
/*      */ import com.zimbra.common.util.Pair;
/*      */ import com.zimbra.common.util.StringUtil;
/*      */ import com.zimbra.common.util.ZimbraLog;
/*      */ import com.zimbra.common.zmime.ZMimeMessage;
/*      */ import com.zimbra.cs.convert.ConversionException;
/*      */ import com.zimbra.cs.db.DbMailItem;
/*      */ import com.zimbra.cs.index.Fragment;
/*      */ import com.zimbra.cs.index.IndexDocument;
/*      */ import com.zimbra.cs.index.ZimbraAnalyzer;
/*      */ import com.zimbra.cs.index.analysis.FieldTokenStream;
/*      */ import com.zimbra.cs.index.analysis.MimeTypeTokenStream;
/*      */ import com.zimbra.cs.index.analysis.RFC822AddressTokenStream;
/*      */ import com.zimbra.cs.mailbox.Flag;
/*      */ import com.zimbra.cs.mailbox.Mailbox;
/*      */ import com.zimbra.cs.mailbox.Threader;
/*      */ import com.zimbra.cs.object.ObjectHandlerException;
/*      */ import com.zimbra.cs.store.Blob;
/*      */ import com.zimbra.cs.store.BlobInputStream;
/*      */ import com.zimbra.cs.store.StoreManager;
/*      */ import com.zimbra.cs.util.JMSession;
/*      */ import java.io.ByteArrayOutputStream;
/*      */ import java.io.File;
/*      */ import java.io.FileInputStream;
/*      */ import java.io.IOException;
/*      */ import java.io.InputStream;
/*      */ import java.text.ParseException;
/*      */ import java.util.ArrayList;
/*      */ import java.util.Collections;
/*      */ import java.util.Date;
/*      */ import java.util.Enumeration;
/*      */ import java.util.HashMap;
/*      */ import java.util.HashSet;
/*      */ import java.util.List;
/*      */ import java.util.Locale;
/*      */ import java.util.Map;
/*      */ import java.util.Set;
/*      */ import java.util.zip.GZIPInputStream;
/*      */ import javax.activation.DataHandler;
/*      */ import javax.mail.Address;
/*      */ import javax.mail.Header;
/*      */ import javax.mail.MessagingException;
/*      */ import javax.mail.internet.AddressException;
/*      */ import javax.mail.internet.MailDateFormat;
/*      */ import javax.mail.internet.MimeMessage;
/*      */ import javax.mail.internet.MimePart;
/*      */ import javax.mail.internet.MimeUtility;
/*      */ import javax.mail.internet.SharedInputStream;
/*      */ import javax.mail.util.SharedByteArrayInputStream;
/*      */ import org.apache.lucene.document.Document;
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ public final class ParsedMessage
/*      */ {
/*      */   private static final Log LOG;
/*      */   private static final MailDateFormat FORMAT;
/*      */   public static final long DATE_HEADER = -2L;
/*      */   public static final long DATE_UNKNOWN = -1L;
/*      */   private MimeMessage mimeMessage;
/*      */   private MimeMessage expandedMessage;
/*  111 */   private boolean parsed = false;
/*  112 */   private boolean analyzedBodyParts = false;
/*  113 */   private boolean analyzedNonBodyParts = false;
/*  114 */   private String bodyContent = "";
/*  115 */   private final List<String> filenames = new ArrayList();
/*      */   private boolean indexAttachments;
/*  117 */   private int numParseErrors = 0;
/*      */   
/*      */ 
/*      */   private String defaultCharset;
/*      */   
/*  122 */   private boolean temporaryAnalysisFailure = false;
/*      */   
/*      */   private List<MPartInfo> messageParts;
/*      */   
/*      */   private String recipients;
/*      */   private String sender;
/*      */   private RFC822AddressTokenStream fromTokenStream;
/*      */   private RFC822AddressTokenStream toTokenStream;
/*      */   private RFC822AddressTokenStream ccTokenStream;
/*      */   private ParsedAddress parsedSender;
/*      */   private List<ParsedAddress> parsedRecipients;
/*  133 */   private boolean hasAttachments = false;
/*  134 */   private boolean hasTextCalendarPart = false;
/*  135 */   private String fragment = "";
/*      */   private boolean encrypted;
/*  137 */   private long dateHeader = -1L;
/*  138 */   private long receivedDate = -1L;
/*      */   private String subject;
/*      */   private String normalizedSubject;
/*      */   private boolean subjectIsReply;
/*  142 */   private Boolean hasReplyToHeader = null;
/*  143 */   private final List<IndexDocument> luceneDocuments = new ArrayList(2);
/*      */   private CalendarPartInfo calendarPartInfo;
/*      */   private boolean wasMutated;
/*      */   private InputStream sharedStream;
/*  147 */   private final Map<Mailbox, Threader> threaders = new HashMap();
/*      */   private static final Set<String> ENCRYPTED_PART_TYPES;
/*      */   
/*  150 */   public ParsedMessage(MimeMessage msg, boolean indexAttachments) throws ServiceException { this(msg, getZimbraDateHeader(msg), indexAttachments); }
/*      */   
/*      */   public ParsedMessage(MimeMessage msg, long receivedDate, boolean indexAttachments) throws ServiceException
/*      */   {
/*  154 */     initialize(msg, Long.valueOf(receivedDate), indexAttachments);
/*      */   }
/*      */   
/*      */   public ParsedMessage(byte[] rawData, boolean indexAttachments) throws ServiceException {
/*  158 */     this(rawData, null, indexAttachments);
/*      */   }
/*      */   
/*      */   public ParsedMessage(byte[] rawData, Long receivedDate, boolean indexAttachments) throws ServiceException {
/*  162 */     initialize(rawData, receivedDate, indexAttachments);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public ParsedMessage(File file, Long receivedDate, boolean indexAttachments)
/*      */     throws ServiceException, IOException
/*      */   {
/*  170 */     initialize(file, receivedDate, indexAttachments);
/*      */   }
/*      */   
/*      */   public ParsedMessage(Blob blob, Long receivedDate, boolean indexAttachments) throws ServiceException, IOException {
/*  174 */     initialize(blob, receivedDate, indexAttachments);
/*      */   }
/*      */   
/*      */   public ParsedMessage(ParsedMessageOptions opt) throws ServiceException {
/*  178 */     if (opt.getAttachmentIndexing() == null) {
/*  179 */       throw ServiceException.FAILURE("Options do not specify attachment indexing state.", null);
/*      */     }
/*      */     
/*  182 */     if (opt.getMimeMessage() != null) {
/*  183 */       initialize(opt.getMimeMessage(), opt.getReceivedDate(), opt.getAttachmentIndexing().booleanValue());
/*  184 */     } else if (opt.getRawData() != null) {
/*  185 */       initialize(opt.getRawData(), opt.getReceivedDate(), opt.getAttachmentIndexing().booleanValue());
/*  186 */     } else if (opt.getFile() != null) {
/*      */       try {
/*  188 */         initialize(opt.getFile(), opt.getReceivedDate(), opt.getAttachmentIndexing().booleanValue());
/*      */       } catch (IOException e) {
/*  190 */         throw ServiceException.FAILURE("Unable to initialize ParsedMessage", e);
/*      */       }
/*      */     } else {
/*  193 */       throw ServiceException.FAILURE("ParsedMessageOptions do not specify message content", null);
/*      */     }
/*      */   }
/*      */   
/*      */   private void initialize(MimeMessage msg, Long receivedDate, boolean indexAttachments) throws ServiceException {
/*  198 */     this.mimeMessage = msg;
/*  199 */     this.expandedMessage = msg;
/*  200 */     initialize(receivedDate, indexAttachments);
/*      */   }
/*      */   
/*      */   private void initialize(byte[] rawData, Long receivedDate, boolean indexAttachments) throws ServiceException {
/*  204 */     if ((rawData == null) || (rawData.length == 0)) {
/*  205 */       throw ServiceException.FAILURE("Message data cannot be null or empty.", null);
/*      */     }
/*  207 */     this.sharedStream = new SharedByteArrayInputStream(rawData);
/*  208 */     initialize(receivedDate, indexAttachments);
/*      */   }
/*      */   
/*      */   private void initialize(Blob blob, Long receivedDate, boolean indexAttachments) throws IOException, ServiceException
/*      */   {
/*  213 */     this.sharedStream = StoreManager.getInstance().getContent(blob);
/*  214 */     initialize(receivedDate, indexAttachments);
/*      */   }
/*      */   
/*      */   private void initialize(File file, Long receivedDate, boolean indexAttachments) throws IOException, ServiceException
/*      */   {
/*  219 */     if (file == null) {
/*  220 */       throw new IOException("File cannot be null.");
/*      */     }
/*  222 */     if (file.length() == 0L) {
/*  223 */       throw new IOException("File " + file.getPath() + " is empty.");
/*      */     }
/*      */     long size;
/*      */     long size;
/*  227 */     if (FileUtil.isGzipped(file)) {
/*  228 */       size = ByteUtil.getDataLength(new GZIPInputStream(new FileInputStream(file)));
/*      */     } else {
/*  230 */       size = file.length();
/*      */     }
/*  232 */     this.sharedStream = new BlobInputStream(file, size);
/*  233 */     initialize(receivedDate, indexAttachments);
/*      */   }
/*      */   
/*      */   private void initialize(Long receivedDate, boolean indexAttachments) throws ServiceException {
/*      */     try {
/*  238 */       init(receivedDate, indexAttachments);
/*      */     } catch (MessagingException e) {
/*  240 */       throw ServiceException.FAILURE("Unable to initialize ParsedMessage", e);
/*      */     } catch (IOException e) {
/*  242 */       throw ServiceException.FAILURE("Unable to initialize ParsedMessage", e);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   private void init(Long receivedDate, boolean indexAttachments)
/*      */     throws MessagingException, IOException
/*      */   {
/*  251 */     this.indexAttachments = indexAttachments;
/*      */     
/*  253 */     if (this.mimeMessage == null) {
/*  254 */       if (this.sharedStream == null) {
/*  255 */         throw new IOException("Content stream has not been initialized.");
/*      */       }
/*  257 */       if (!(this.sharedStream instanceof SharedInputStream)) {
/*  258 */         InputStream in = this.sharedStream;
/*  259 */         this.sharedStream = null;
/*  260 */         byte[] content = ByteUtil.getContent(in, 0);
/*  261 */         this.sharedStream = new SharedByteArrayInputStream(content);
/*      */       }
/*      */       
/*  264 */       this.mimeMessage = (this.expandedMessage = new Mime.FixedMimeMessage(JMSession.getSession(), this.sharedStream));
/*      */     }
/*      */     
/*      */     try
/*      */     {
/*  269 */       runMimeMutators();
/*      */     } catch (Exception e) {
/*  271 */       this.wasMutated = false;
/*      */       
/*  273 */       this.mimeMessage = (this.expandedMessage = new Mime.FixedMimeMessage(JMSession.getSession(), getRawInputStream()));
/*      */     }
/*      */     
/*  276 */     if (wasMutated())
/*      */     {
/*  278 */       ByteArrayOutputStream buffer = new ByteArrayOutputStream();
/*  279 */       this.mimeMessage.writeTo(buffer);
/*  280 */       byte[] content = buffer.toByteArray();
/*  281 */       ByteUtil.closeStream(this.sharedStream);
/*  282 */       this.sharedStream = new SharedByteArrayInputStream(content);
/*  283 */       this.mimeMessage = (this.expandedMessage = null);
/*  284 */       this.mimeMessage = (this.expandedMessage = new Mime.FixedMimeMessage(JMSession.getSession(), this.sharedStream));
/*      */     }
/*      */     
/*  287 */     ExpandMimeMessage expand = new ExpandMimeMessage(this.mimeMessage);
/*      */     try {
/*  289 */       expand.expand();
/*  290 */       this.expandedMessage = expand.getExpanded();
/*      */     }
/*      */     catch (Exception e) {
/*  293 */       this.expandedMessage = this.mimeMessage;
/*  294 */       LOG.warn("exception while converting message; message will be analyzed unconverted", e);
/*      */     }
/*      */     
/*      */ 
/*  298 */     if (receivedDate == null) {
/*  299 */       receivedDate = Long.valueOf(getZimbraDateHeader(this.mimeMessage));
/*      */     }
/*  301 */     setReceivedDate(receivedDate.longValue());
/*      */   }
/*      */   
/*      */   public boolean wasMutated() {
/*  305 */     return this.wasMutated;
/*      */   }
/*      */   
/*      */   public ParsedMessage setDefaultCharset(String charset) {
/*  309 */     this.defaultCharset = charset;
/*  310 */     if ((this.mimeMessage instanceof ZMimeMessage)) {
/*  311 */       ((ZMimeMessage)this.mimeMessage).setProperty("mail.mime.charset", charset);
/*      */     }
/*  313 */     if ((this.expandedMessage != this.mimeMessage) && ((this.expandedMessage instanceof ZMimeMessage))) {
/*  314 */       ((ZMimeMessage)this.expandedMessage).setProperty("mail.mime.charset", charset);
/*      */     }
/*  316 */     this.subject = (this.normalizedSubject = null);
/*  317 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private ParsedMessage parse()
/*      */   {
/*  328 */     if (this.parsed) {
/*  329 */       return this;
/*      */     }
/*  331 */     this.parsed = true;
/*      */     try
/*      */     {
/*  334 */       this.messageParts = Mime.getParts(this.expandedMessage);
/*  335 */       this.hasAttachments = Mime.hasAttachment(this.messageParts);
/*  336 */       this.hasTextCalendarPart = Mime.hasTextCalenndar(this.messageParts);
/*      */     } catch (Exception e) {
/*  338 */       ZimbraLog.index.warn("exception while parsing message; message will not be indexed", e);
/*  339 */       this.messageParts = new ArrayList();
/*      */     }
/*  341 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private void runMimeMutators()
/*      */     throws MessagingException
/*      */   {
/*  353 */     this.wasMutated = false;
/*  354 */     for (Class<? extends MimeVisitor> vclass : MimeVisitor.getMutators()) {
/*      */       try {
/*  356 */         this.wasMutated |= ((MimeVisitor)vclass.newInstance()).accept(this.mimeMessage);
/*  357 */         if (this.mimeMessage != this.expandedMessage) {
/*  358 */           ((MimeVisitor)vclass.newInstance()).accept(this.expandedMessage);
/*      */         }
/*      */       } catch (MessagingException e) {
/*  361 */         throw e;
/*      */       } catch (Exception e) {
/*  363 */         ZimbraLog.misc.warn("exception ignored running mutator; skipping", e);
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private void analyzeBodyParts()
/*      */     throws ServiceException
/*      */   {
/*  377 */     if (this.analyzedBodyParts) {
/*  378 */       return;
/*      */     }
/*      */     
/*  381 */     this.analyzedBodyParts = true;
/*  382 */     if (DebugConfig.disableMessageAnalysis) {
/*  383 */       return;
/*      */     }
/*      */     
/*  386 */     parse();
/*      */     try
/*      */     {
/*  389 */       Set<MPartInfo> mpiBodies = Mime.getBody(this.messageParts, false);
/*      */       
/*      */ 
/*  392 */       StringBuilder body = new StringBuilder();
/*  393 */       for (MPartInfo mpi : this.messageParts) {
/*  394 */         if (mpiBodies.contains(mpi)) {
/*  395 */           String toplevelText = analyzePart(true, mpi);
/*  396 */           if (toplevelText.length() > 0) {
/*  397 */             appendToContent(body, toplevelText);
/*      */           }
/*      */         }
/*  400 */         if (ENCRYPTED_PART_TYPES.contains(mpi.mContentType)) {
/*  401 */           this.encrypted = true;
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*  406 */       this.bodyContent = body.toString().trim();
/*  407 */       this.fragment = Fragment.getFragment(this.bodyContent, this.hasTextCalendarPart);
/*      */     } catch (ServiceException e) {
/*  409 */       throw e;
/*      */     } catch (Exception e) {
/*  411 */       LOG.warn("exception while analyzing message; message will be partially indexed", e);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   private void analyzeNonBodyParts()
/*      */     throws ServiceException
/*      */   {
/*  419 */     if (this.analyzedNonBodyParts) {
/*  420 */       return;
/*      */     }
/*      */     
/*  423 */     this.analyzedNonBodyParts = true;
/*  424 */     if (DebugConfig.disableMessageAnalysis) {
/*  425 */       return;
/*      */     }
/*      */     
/*  428 */     analyzeBodyParts();
/*      */     try
/*      */     {
/*  431 */       Set<MPartInfo> mpiBodies = Mime.getBody(this.messageParts, false);
/*      */       
/*      */ 
/*  434 */       StringBuilder fullContent = new StringBuilder(this.bodyContent);
/*      */       
/*  436 */       for (MPartInfo mpi : this.messageParts) {
/*  437 */         boolean isMainBody = mpiBodies.contains(mpi);
/*  438 */         if (!isMainBody) {
/*  439 */           String toplevelText = analyzePart(isMainBody, mpi);
/*  440 */           if (toplevelText.length() > 0) {
/*  441 */             appendToContent(fullContent, toplevelText);
/*      */           }
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*  448 */       this.luceneDocuments.add(getMainBodyLuceneDocument(fullContent));
/*      */       
/*      */ 
/*  451 */       this.bodyContent = "";
/*      */       
/*  453 */       if (this.numParseErrors > 0) {
/*  454 */         LOG.warn("Message had analysis errors in %d parts (Message-Id: %s, Subject: %s)", new Object[] { Integer.valueOf(this.numParseErrors), getMessageID(), getSubject() });
/*      */       }
/*      */     }
/*      */     catch (ServiceException e) {
/*  458 */       throw e;
/*      */     } catch (Exception e) {
/*  460 */       LOG.warn("exception while analyzing message; message will be partially indexed", e);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public void analyzeFully()
/*      */     throws ServiceException
/*      */   {
/*  470 */     analyzeNonBodyParts();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public MimeMessage getMimeMessage()
/*      */   {
/*  477 */     return this.expandedMessage;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public MimeMessage getOriginalMessage()
/*      */   {
/*  484 */     return this.mimeMessage;
/*      */   }
/*      */   
/*      */ 
/*      */   public byte[] getRawData()
/*      */     throws IOException
/*      */   {
/*  491 */     return ByteUtil.getContent(getRawInputStream(), 1024);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   private static final Set<String> SYSTEM_PREFIXES;
/*      */   
/*      */ 
/*      */   private static final int MAX_PREFIX_LENGTH = 3;
/*      */   
/*      */ 
/*      */   public InputStream getRawInputStream()
/*      */     throws IOException
/*      */   {
/*  506 */     if (this.sharedStream != null) {
/*  507 */       return ((SharedInputStream)this.sharedStream).newStream(0L, -1L);
/*      */     }
/*  509 */     return Mime.getInputStream(this.mimeMessage);
/*      */   }
/*      */   
/*      */   public boolean isAttachmentIndexingEnabled()
/*      */   {
/*  514 */     return this.indexAttachments;
/*      */   }
/*      */   
/*      */   public List<MPartInfo> getMessageParts() {
/*  518 */     parse();
/*  519 */     return this.messageParts;
/*      */   }
/*      */   
/*      */   public boolean hasAttachments() {
/*  523 */     parse();
/*  524 */     return this.hasAttachments;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public BlobInputStream getBlobInputStream()
/*      */   {
/*  531 */     if ((this.sharedStream instanceof BlobInputStream)) {
/*  532 */       return (BlobInputStream)this.sharedStream;
/*      */     }
/*  534 */     return null;
/*      */   }
/*      */   
/*      */   public boolean isStreamedFromDisk() {
/*  538 */     return getBlobInputStream() != null;
/*      */   }
/*      */   
/*      */   public int getPriorityBitmask() {
/*  542 */     MimeMessage mm = getMimeMessage();
/*      */     try
/*      */     {
/*  545 */       String xprio = mm.getHeader("X-Priority", null);
/*  546 */       if (xprio != null) {
/*  547 */         xprio = xprio.trim();
/*  548 */         if ((xprio.startsWith("1")) || (xprio.startsWith("2")))
/*  549 */           return Flag.BITMASK_HIGH_PRIORITY;
/*  550 */         if (xprio.startsWith("3"))
/*  551 */           return 0;
/*  552 */         if ((xprio.startsWith("4")) || (xprio.startsWith("5"))) {
/*  553 */           return Flag.BITMASK_LOW_PRIORITY;
/*      */         }
/*      */       }
/*      */     }
/*      */     catch (MessagingException e) {}
/*      */     try
/*      */     {
/*  560 */       String impt = mm.getHeader("Importance", null);
/*  561 */       if (impt != null) {
/*  562 */         impt = impt.trim().toLowerCase();
/*  563 */         if (impt.startsWith("high"))
/*  564 */           return Flag.BITMASK_HIGH_PRIORITY;
/*  565 */         if (impt.startsWith("normal"))
/*  566 */           return 0;
/*  567 */         if (impt.startsWith("low")) {
/*  568 */           return Flag.BITMASK_LOW_PRIORITY;
/*      */         }
/*      */       }
/*      */     }
/*      */     catch (MessagingException e) {}
/*      */     
/*  574 */     return 0;
/*      */   }
/*      */   
/*      */   public boolean isList(String envSenderString) {
/*  578 */     MimeMessage mm = getMimeMessage();
/*      */     try
/*      */     {
/*  581 */       if (mm.getHeader("List-ID") != null) {
/*  582 */         return true;
/*      */       }
/*      */     }
/*      */     catch (MessagingException e) {}
/*      */     try
/*      */     {
/*  588 */       if ("list".equalsIgnoreCase(mm.getHeader("Precedence", null))) {
/*  589 */         return true;
/*      */       }
/*      */     }
/*      */     catch (MessagingException e) {}
/*      */     
/*  594 */     if (envSenderString != null) {
/*      */       try
/*      */       {
/*  597 */         javax.mail.internet.InternetAddress envSender = new JavaMailInternetAddress(envSenderString, true);
/*  598 */         if (envSender.getAddress() != null) {
/*  599 */           String[] envSenderAddrParts = EmailUtil.getLocalPartAndDomain(envSender.getAddress());
/*  600 */           if (envSenderAddrParts != null) {
/*  601 */             String sender = envSenderAddrParts[0].toLowerCase();
/*  602 */             if ((sender.startsWith("owner-")) || (sender.endsWith("-owner")) || (sender.indexOf("-request") != -1) || (sender.equals("mailer-daemon")) || (sender.equals("majordomo")) || (sender.equals("listserv")))
/*      */             {
/*      */ 
/*  605 */               return true;
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/*      */       catch (AddressException e) {}
/*      */     }
/*      */     
/*  613 */     return false;
/*      */   }
/*      */   
/*      */   private boolean isInReplyTo() {
/*  617 */     if (this.hasReplyToHeader != null) {
/*  618 */       return this.hasReplyToHeader.booleanValue();
/*      */     }
/*      */     try
/*      */     {
/*  622 */       String[] replyTo = getMimeMessage().getHeader("In-Reply-To");
/*  623 */       this.hasReplyToHeader = Boolean.valueOf((replyTo != null) && (replyTo.length > 0) && (replyTo[0].length() > 0));
/*  624 */       return this.hasReplyToHeader.booleanValue();
/*      */     } catch (MessagingException e) {
/*  626 */       LOG.warn("messaging exception getting In-Reply-To header", e); }
/*  627 */     return false;
/*      */   }
/*      */   
/*      */   public boolean isReply()
/*      */   {
/*  632 */     normalizeSubject();
/*  633 */     return (this.subjectIsReply) || (isInReplyTo());
/*      */   }
/*      */   
/*      */   public String getSubject() {
/*  637 */     normalizeSubject();
/*  638 */     return this.subject;
/*      */   }
/*      */   
/*      */   public String getNormalizedSubject() {
/*  642 */     normalizeSubject();
/*  643 */     return this.normalizedSubject;
/*      */   }
/*      */   
/*      */   public String getFragment(Locale lc) {
/*      */     try {
/*  648 */       analyzeBodyParts();
/*      */     } catch (ServiceException e) {
/*  650 */       LOG.warn("Message analysis failed when getting fragment; fragment is: %s", this.fragment, e);
/*      */     }
/*      */     
/*  653 */     if ((this.encrypted) && (this.fragment.isEmpty())) {
/*  654 */       return Strings.nullToEmpty(L10nUtil.getMessage(L10nUtil.MsgKey.encryptedMessageFragment, lc, new Object[0]));
/*      */     }
/*  656 */     return this.fragment;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public String getMessageID()
/*      */   {
/*  663 */     return Mime.getMessageID(getMimeMessage());
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public Set<String> getAllReferences()
/*      */   {
/*  674 */     MimeMessage mm = getMimeMessage();
/*      */     
/*  676 */     Set<String> refs = new HashSet();
/*  677 */     refs.addAll(Mime.getReferences(mm, "Message-ID"));
/*  678 */     refs.addAll(Mime.getReferences(mm, "In-Reply-To"));
/*  679 */     refs.addAll(Mime.getReferences(mm, "References"));
/*  680 */     refs.addAll(Mime.getReferences(mm, "Resent-Message-ID"));
/*      */     
/*  682 */     refs.remove(null);
/*  683 */     refs.remove("");
/*  684 */     return refs;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public String getRecipients()
/*      */   {
/*  691 */     if (this.recipients == null) {
/*      */       try {
/*  693 */         this.recipients = getMimeMessage().getHeader("To", ", ");
/*      */       } catch (MessagingException e) {
/*  695 */         this.recipients = "";
/*      */       }
/*      */     }
/*  698 */     return this.recipients;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public List<ParsedAddress> getParsedRecipients()
/*      */   {
/*  705 */     if (this.parsedRecipients == null) {
/*  706 */       List<com.zimbra.common.mime.InternetAddress> addrs = com.zimbra.common.mime.InternetAddress.parseHeader(getRecipients());
/*      */       
/*  708 */       if (addrs != null) {
/*  709 */         this.parsedRecipients = new ArrayList(addrs.size());
/*  710 */         for (com.zimbra.common.mime.InternetAddress addr : addrs) {
/*  711 */           this.parsedRecipients.add(new ParsedAddress(addr).parse());
/*      */         }
/*      */       } else {
/*  714 */         this.parsedRecipients = Collections.emptyList();
/*      */       }
/*      */     }
/*  717 */     return this.parsedRecipients;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public String getSender()
/*      */   {
/*  724 */     if (this.sender == null) {
/*  725 */       this.sender = Mime.getSender(getMimeMessage());
/*      */     }
/*  727 */     return this.sender;
/*      */   }
/*      */   
/*      */   private RFC822AddressTokenStream getFromTokenStream() {
/*  731 */     if (this.fromTokenStream != null) {
/*  732 */       return new RFC822AddressTokenStream(this.fromTokenStream);
/*      */     }
/*      */     
/*  735 */     String from = null;
/*      */     try {
/*  737 */       from = getMimeMessage().getHeader("From", null);
/*      */     }
/*      */     catch (MessagingException ignore) {}
/*  740 */     if (from == null) {
/*      */       try {
/*  742 */         from = getMimeMessage().getHeader("Sender", null);
/*      */       }
/*      */       catch (MessagingException ignore) {}
/*      */     }
/*  746 */     return this.fromTokenStream = new RFC822AddressTokenStream(from);
/*      */   }
/*      */   
/*      */   private RFC822AddressTokenStream getToTokenStream() {
/*  750 */     if (this.toTokenStream != null) {
/*  751 */       return new RFC822AddressTokenStream(this.toTokenStream);
/*      */     }
/*      */     
/*  754 */     String to = null;
/*      */     try {
/*  756 */       to = getMimeMessage().getHeader("To", ",");
/*      */     }
/*      */     catch (MessagingException ignore) {}
/*  759 */     return this.toTokenStream = new RFC822AddressTokenStream(to);
/*      */   }
/*      */   
/*      */   private RFC822AddressTokenStream getCcTokenStream() {
/*  763 */     if (this.ccTokenStream != null) {
/*  764 */       return new RFC822AddressTokenStream(this.ccTokenStream);
/*      */     }
/*      */     
/*  767 */     String cc = null;
/*      */     try {
/*  769 */       cc = getMimeMessage().getHeader("Cc", ",");
/*      */     }
/*      */     catch (MessagingException ignore) {}
/*  772 */     return this.ccTokenStream = new RFC822AddressTokenStream(cc);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public String getSenderEmail()
/*      */   {
/*  780 */     return getSenderEmail(true);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public String getSenderEmail(boolean fromFirst)
/*      */   {
/*      */     try
/*      */     {
/*  790 */       if (fromFirst)
/*      */       {
/*  792 */         Address[] froms = getMimeMessage().getFrom();
/*  793 */         if ((froms != null) && (froms.length > 0) && ((froms[0] instanceof javax.mail.internet.InternetAddress))) {
/*  794 */           return ((javax.mail.internet.InternetAddress)froms[0]).getAddress();
/*      */         }
/*  796 */         Address sender = getMimeMessage().getSender();
/*  797 */         if ((sender instanceof javax.mail.internet.InternetAddress)) {
/*  798 */           return ((javax.mail.internet.InternetAddress)sender).getAddress();
/*      */         }
/*      */       }
/*      */       else {
/*  802 */         Address sender = getMimeMessage().getSender();
/*  803 */         if ((sender instanceof javax.mail.internet.InternetAddress)) {
/*  804 */           return ((javax.mail.internet.InternetAddress)sender).getAddress();
/*      */         }
/*  806 */         Address[] froms = getMimeMessage().getFrom();
/*  807 */         if ((froms != null) && (froms.length > 0) && ((froms[0] instanceof javax.mail.internet.InternetAddress))) {
/*  808 */           return ((javax.mail.internet.InternetAddress)froms[0]).getAddress();
/*      */         }
/*      */       }
/*      */     }
/*      */     catch (MessagingException e) {}
/*      */     
/*  814 */     return null;
/*      */   }
/*      */   
/*      */   public ParsedAddress getParsedSender() {
/*  818 */     if (this.parsedSender == null) {
/*  819 */       this.parsedSender = new ParsedAddress(getSender()).parse();
/*      */     }
/*  821 */     return this.parsedSender;
/*      */   }
/*      */   
/*      */   public String getReplyTo() {
/*  825 */     String replyTo = null;
/*      */     try {
/*  827 */       replyTo = getMimeMessage().getHeader("Reply-To", null);
/*  828 */       if ((replyTo == null) || (replyTo.trim().isEmpty())) {
/*  829 */         return null;
/*      */       }
/*      */     }
/*      */     catch (Exception e) {}
/*      */     
/*  834 */     String sender = getSender();
/*  835 */     if ((sender != null) && (sender.equals(replyTo))) {
/*  836 */       return null;
/*      */     }
/*  838 */     return replyTo;
/*      */   }
/*      */   
/*      */   public long getDateHeader() {
/*  842 */     if (this.dateHeader != -1L) {
/*  843 */       return this.dateHeader;
/*      */     }
/*  845 */     this.dateHeader = getReceivedDate();
/*      */     try {
/*  847 */       Date date = getMimeMessage().getSentDate();
/*  848 */       if (date != null)
/*      */       {
/*  850 */         this.dateHeader = Math.max(date.getTime(), 0L);
/*      */       }
/*      */     }
/*      */     catch (MessagingException e) {}
/*      */     
/*  855 */     return this.dateHeader;
/*      */   }
/*      */   
/*      */   public ParsedMessage setReceivedDate(long date)
/*      */   {
/*  860 */     if (date == -2L) {
/*  861 */       this.receivedDate = getDateHeader();
/*  862 */     } else if (date != -1L) {
/*  863 */       this.receivedDate = (Math.max(0L, date) / 1000L * 1000L);
/*      */     }
/*  865 */     return this;
/*      */   }
/*      */   
/*      */   public long getReceivedDate() {
/*  869 */     if (this.receivedDate == -1L) {
/*  870 */       this.receivedDate = System.currentTimeMillis();
/*      */     }
/*  872 */     assert (this.receivedDate >= 0L) : this.receivedDate;
/*  873 */     return this.receivedDate;
/*      */   }
/*      */   
/*      */   private static long getZimbraDateHeader(MimeMessage mm) {
/*  877 */     String zimbraHeader = null;
/*      */     try {
/*  879 */       zimbraHeader = mm.getHeader("X-Zimbra-Received", null);
/*  880 */       if ((zimbraHeader == null) || (zimbraHeader.trim().isEmpty())) {
/*  881 */         return -1L;
/*      */       }
/*      */     } catch (MessagingException mex) {
/*  884 */       return -1L;
/*      */     }
/*      */     
/*  887 */     Date zimbraDate = null;
/*  888 */     synchronized (FORMAT) {
/*      */       try {
/*  890 */         zimbraDate = FORMAT.parse(zimbraHeader);
/*      */       } catch (ParseException e) {
/*  892 */         return -1L;
/*      */       }
/*      */     }
/*  895 */     return zimbraDate == null ? -1L : zimbraDate.getTime();
/*      */   }
/*      */   
/*      */   public List<IndexDocument> getLuceneDocuments() {
/*      */     try {
/*  900 */       analyzeFully();
/*      */     } catch (ServiceException e) {
/*  902 */       LOG.warn("message analysis failed when getting lucene documents");
/*      */     }
/*  904 */     return this.luceneDocuments;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public CalendarPartInfo getCalendarPartInfo()
/*      */   {
/*      */     try
/*      */     {
/*  916 */       parse();
/*  917 */       if (this.hasTextCalendarPart) {
/*  918 */         analyzeFully();
/*      */       }
/*      */     }
/*      */     catch (ServiceException e) {
/*  922 */       LOG.warn("Message analysis failed when getting calendar info");
/*      */     }
/*  924 */     return this.calendarPartInfo;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public boolean hasTemporaryAnalysisFailure()
/*      */     throws ServiceException
/*      */   {
/*  933 */     analyzeFully();
/*  934 */     return this.temporaryAnalysisFailure;
/*      */   }
/*      */   
/*      */   private IndexDocument getMainBodyLuceneDocument(StringBuilder fullContent)
/*      */     throws MessagingException, ServiceException
/*      */   {
/*  940 */     IndexDocument doc = new IndexDocument(new Document());
/*  941 */     doc.addMimeType(new MimeTypeTokenStream("message/rfc822"));
/*  942 */     doc.addPartName("top");
/*  943 */     doc.addFrom(getFromTokenStream());
/*  944 */     doc.addTo(getToTokenStream());
/*  945 */     doc.addCc(getCcTokenStream());
/*      */     try {
/*  947 */       doc.addEnvFrom(new RFC822AddressTokenStream(getMimeMessage().getHeader("X-Envelope-From", ",")));
/*      */     }
/*      */     catch (MessagingException ignore) {}
/*      */     try {
/*  951 */       doc.addEnvTo(new RFC822AddressTokenStream(getMimeMessage().getHeader("X-Envelope-To", ",")));
/*      */     }
/*      */     catch (MessagingException ignore) {}
/*      */     
/*  955 */     String msgId = Strings.nullToEmpty(Mime.getHeader(getMimeMessage(), "message-id"));
/*  956 */     if (msgId.length() > 0) {
/*  957 */       if (msgId.charAt(0) == '<') {
/*  958 */         msgId = msgId.substring(1);
/*      */       }
/*  960 */       if (msgId.charAt(msgId.length() - 1) == '>') {
/*  961 */         msgId = msgId.substring(0, msgId.length() - 1);
/*      */       }
/*  963 */       if (msgId.length() > 0) {
/*  964 */         doc.addMessageId(msgId);
/*      */       }
/*      */     }
/*      */     
/*      */ 
/*  969 */     FieldTokenStream fields = new FieldTokenStream();
/*  970 */     Enumeration<?> en = getMimeMessage().getAllHeaders();
/*  971 */     while (en.hasMoreElements()) {
/*  972 */       Header h = (Header)en.nextElement();
/*  973 */       String key = h.getName().trim();
/*  974 */       String value = h.getValue();
/*  975 */       if (value != null) {
/*  976 */         value = MimeUtility.unfold(value).trim();
/*      */       } else {
/*  978 */         value = "";
/*      */       }
/*  980 */       if (key.length() > 0) {
/*  981 */         if (value.length() == 0)
/*      */         {
/*      */ 
/*      */ 
/*      */ 
/*  986 */           fields.add(key, "_blank_");
/*      */         } else {
/*  988 */           fields.add(key, value);
/*      */         }
/*      */       }
/*      */     }
/*      */     
/*  993 */     doc.addField(fields);
/*      */     
/*  995 */     String subject = getSubject();
/*  996 */     doc.addSubject(subject);
/*      */     
/*      */ 
/*  999 */     StringBuilder contentPrepend = new StringBuilder(subject);
/*      */     
/*      */ 
/* 1002 */     appendToContent(contentPrepend, StringUtil.join(" ", getFromTokenStream().getAllTokens()));
/* 1003 */     appendToContent(contentPrepend, StringUtil.join(" ", getToTokenStream().getAllTokens()));
/* 1004 */     appendToContent(contentPrepend, StringUtil.join(" ", getCcTokenStream().getAllTokens()));
/*      */     
/*      */ 
/* 1007 */     for (String fn : this.filenames) {
/* 1008 */       appendToContent(contentPrepend, ZimbraAnalyzer.getAllTokensConcatenated("filename", fn));
/* 1009 */       appendToContent(contentPrepend, fn);
/*      */     }
/*      */     
/* 1012 */     String text = contentPrepend.toString() + " " + fullContent.toString();
/* 1013 */     doc.addContent(text);
/*      */     try
/*      */     {
/* 1016 */       MimeHandler.getObjects(text, doc);
/*      */     } catch (ObjectHandlerException e) {
/* 1018 */       ZimbraLog.index.warn("Unable to recognize searchable objects in message: msgid=%s,subject=%s", getMessageID(), getSubject(), e);
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 1023 */     doc.addAttachments(new MimeTypeTokenStream(Mime.getAttachmentTypeList(this.messageParts)));
/* 1024 */     return doc;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private IndexDocument setLuceneHeadersFromContainer(IndexDocument doc)
/*      */   {
/* 1036 */     doc.addFrom(getFromTokenStream());
/* 1037 */     doc.addTo(getToTokenStream());
/* 1038 */     doc.addCc(getCcTokenStream());
/*      */     
/* 1040 */     String subject = getNormalizedSubject();
/* 1041 */     if (!Strings.isNullOrEmpty(subject)) {
/* 1042 */       doc.addSubject(subject);
/*      */     }
/*      */     
/* 1045 */     return doc;
/*      */   }
/*      */   
/*      */   private static boolean isBouncedCalendar(MPartInfo mpi) {
/* 1049 */     if ("text/calendar".equals(mpi.getContentType())) {
/* 1050 */       MPartInfo parent = mpi;
/* 1051 */       while ((parent = parent.getParent()) != null) {
/* 1052 */         String ct = parent.getContentType();
/* 1053 */         if ("multipart/report".equals(ct))
/* 1054 */           return true;
/*      */       }
/*      */     }
/* 1057 */     return false;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private void setCalendarPartInfo(MPartInfo mpi, ZCalendar.ZVCalendar cal)
/*      */   {
/* 1067 */     this.calendarPartInfo = new CalendarPartInfo();
/* 1068 */     this.calendarPartInfo.cal = cal;
/* 1069 */     this.calendarPartInfo.method = cal.getMethod();
/* 1070 */     this.calendarPartInfo.wasForwarded = false;
/* 1071 */     MPartInfo parent = mpi;
/* 1072 */     while ((parent = parent.getParent()) != null) {
/* 1073 */       if (parent.isMessage()) {
/* 1074 */         this.calendarPartInfo.wasForwarded = true;
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   private String analyzePart(boolean isMainBody, MPartInfo mpi)
/*      */     throws MessagingException, ServiceException
/*      */   {
/*      */     boolean ignoreCalendar;
/*      */     boolean ignoreCalendar;
/* 1085 */     if (this.calendarPartInfo == null) {
/* 1086 */       ignoreCalendar = isBouncedCalendar(mpi);
/*      */     } else {
/* 1088 */       ignoreCalendar = true;
/*      */     }
/* 1090 */     String methodParam = new ContentType(mpi.getMimePart().getContentType()).getParameter("method");
/* 1091 */     if ((methodParam == null) && (!LC.calendar_allow_invite_without_method.booleanValue())) {
/* 1092 */       ignoreCalendar = true;
/*      */     }
/* 1094 */     String toRet = "";
/*      */     try
/*      */     {
/* 1097 */       if (mpi.isMultipart()) {
/* 1098 */         return toRet;
/*      */       }
/* 1100 */       String ctype = mpi.getContentType();
/* 1101 */       MimeHandler handler = MimeHandlerManager.getMimeHandler(ctype, mpi.getFilename());
/* 1102 */       assert (handler != null);
/* 1103 */       handler.setDefaultCharset(this.defaultCharset);
/*      */       
/* 1105 */       Mime.repairTransferEncoding(mpi.getMimePart());
/*      */       
/* 1107 */       if (handler.isIndexingEnabled()) {
/* 1108 */         handler.init(mpi.getMimePart().getDataHandler().getDataSource());
/* 1109 */         handler.setPartName(mpi.getPartName());
/* 1110 */         handler.setFilename(mpi.getFilename());
/* 1111 */         handler.setSize(mpi.getSize());
/*      */         
/*      */ 
/* 1114 */         if ((!ignoreCalendar) && (this.calendarPartInfo == null)) {
/* 1115 */           ZCalendar.ZVCalendar cal = handler.getICalendar();
/* 1116 */           if (cal != null) {
/* 1117 */             setCalendarPartInfo(mpi, cal);
/*      */           }
/*      */         }
/*      */         
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 1133 */         if (((isMainBody) && ((!handler.runsExternally()) || (this.indexAttachments))) || ((this.indexAttachments) && (!DebugConfig.disableIndexingAttachmentsTogether)))
/*      */         {
/* 1135 */           toRet = handler.getContent();
/*      */         }
/*      */         
/* 1138 */         if ((this.indexAttachments) && (!DebugConfig.disableIndexingAttachmentsSeparately))
/*      */         {
/*      */ 
/*      */ 
/*      */ 
/* 1143 */           IndexDocument doc = new IndexDocument(handler.getDocument());
/*      */           
/* 1145 */           String filename = handler.getFilename();
/* 1146 */           if (!Strings.isNullOrEmpty(filename)) {
/* 1147 */             this.filenames.add(filename);
/*      */           }
/* 1149 */           doc.addSortSize(mpi.getMimePart().getSize());
/* 1150 */           this.luceneDocuments.add(setLuceneHeadersFromContainer(doc));
/*      */         }
/*      */       }
/*      */       
/*      */ 
/* 1155 */       if ((!ignoreCalendar) && (this.calendarPartInfo == null) && (ctype.equals("text/calendar"))) {
/* 1156 */         if (handler.isIndexingEnabled()) {
/* 1157 */           ZimbraLog.index.warn("TextCalendarHandler not correctly installed");
/*      */         }
/* 1159 */         InputStream is = null;
/*      */         try {
/* 1161 */           String charset = mpi.getContentTypeParameter("charset");
/* 1162 */           if ((charset == null) || (charset.trim().isEmpty())) {
/* 1163 */             charset = "us-ascii";
/*      */           }
/* 1165 */           is = mpi.getMimePart().getInputStream();
/* 1166 */           ZCalendar.ZVCalendar cal = ZCalendar.ZCalendarBuilder.build(is, charset);
/* 1167 */           if (cal != null) {
/* 1168 */             setCalendarPartInfo(mpi, cal);
/*      */           }
/*      */         } catch (IOException ioe) {
/* 1171 */           ZimbraLog.index.warn("error reading text/calendar mime part", ioe);
/*      */         } finally {
/* 1173 */           ByteUtil.closeStream(is);
/*      */         }
/*      */       }
/*      */     } catch (MimeHandlerException e) {
/* 1177 */       handleParseError(mpi, e);
/*      */     } catch (ObjectHandlerException e) {
/* 1179 */       handleParseError(mpi, e);
/*      */     }
/* 1181 */     return toRet;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private void handleParseError(MPartInfo mpi, Throwable error)
/*      */   {
/* 1191 */     this.numParseErrors += 1;
/*      */     
/* 1193 */     LOG.warn("Unable to parse part=%s filename=%s content-type=%s message-id=%s", mpi.getPartName(), mpi.getFilename(), mpi.getContentType(), getMessageID(), error);
/*      */     
/* 1195 */     if (ConversionException.isTemporaryCauseOf(error)) {
/* 1196 */       this.temporaryAnalysisFailure = true;
/*      */     }
/*      */     
/* 1199 */     if (!Strings.isNullOrEmpty(mpi.getFilename())) {
/* 1200 */       this.filenames.add(mpi.getFilename());
/*      */     }
/*      */     
/* 1203 */     IndexDocument doc = new IndexDocument(new Document());
/* 1204 */     doc.addMimeType(new MimeTypeTokenStream(mpi.getContentType()));
/* 1205 */     doc.addPartName(mpi.getPartName());
/* 1206 */     doc.addFilename(mpi.getFilename());
/*      */     try {
/* 1208 */       doc.addSortSize(mpi.getMimePart().getSize());
/*      */     }
/*      */     catch (MessagingException ignore) {}
/* 1211 */     this.luceneDocuments.add(setLuceneHeadersFromContainer(doc));
/*      */   }
/*      */   
/*      */   private static final void appendToContent(StringBuilder sb, String s) {
/* 1215 */     if (sb.length() > 0) {
/* 1216 */       sb.append(' ');
/*      */     }
/* 1218 */     sb.append(s);
/*      */   }
/*      */   
/*      */   static
/*      */   {
/*  104 */     LOG = LogFactory.getLog(ParsedMessage.class);
/*  105 */     FORMAT = new MailDateFormat();
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  368 */     ENCRYPTED_PART_TYPES = ImmutableSet.of("application/pkcs7-mime", "application/pgp-encrypted", "multipart/encrypted");
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 1222 */     SYSTEM_PREFIXES = Sets.newHashSet(new String[] { "accept:", "accepted:", "decline:", "declined:", "tentative:", "cancelled:", "new time proposed:", "read-receipt:", "share created:", "share accepted:" });
/*      */     
/*      */ 
/*      */ 
/* 1226 */     for (String localized : L10nUtil.getMessagesAllLocales(new L10nUtil.MsgKey[] { L10nUtil.MsgKey.calendarSubjectCancelled, L10nUtil.MsgKey.calendarReplySubjectAccept, L10nUtil.MsgKey.calendarReplySubjectDecline, L10nUtil.MsgKey.calendarReplySubjectTentative, L10nUtil.MsgKey.shareNotifSubject }))
/*      */     {
/*      */ 
/* 1229 */       SYSTEM_PREFIXES.add(localized.trim().toLowerCase() + ":");
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   @VisibleForTesting
/*      */   static Pair<String, Boolean> trimPrefixes(String subject)
/*      */   {
/* 1237 */     if (Strings.isNullOrEmpty(subject)) {
/* 1238 */       return new Pair("", Boolean.valueOf(false));
/*      */     }
/* 1240 */     boolean trimmed = false;
/*      */     for (;;) {
/* 1242 */       subject = subject.trim();
/* 1243 */       if (subject.length() == 0) {
/* 1244 */         return new Pair(subject, Boolean.valueOf(trimmed));
/*      */       }
/*      */       
/* 1247 */       int tstart = subject.length() - 5;
/*      */       char c;
/* 1249 */       if ((tstart >= 0) && (subject.charAt(tstart) == '(') && (((c = subject.charAt(tstart + 1)) == 'f') || (c == 'F')) && (((c = subject.charAt(tstart + 2)) == 'w') || (c == 'W')) && (((c = subject.charAt(tstart + 3)) == 'd') || (c == 'D')) && (subject.charAt(tstart + 4) == ')'))
/*      */       {
/*      */ 
/*      */ 
/*      */ 
/* 1254 */         subject = subject.substring(0, subject.length() - 5).trim();
/* 1255 */         trimmed = true;
/*      */ 
/*      */       }
/*      */       else
/*      */       {
/* 1260 */         boolean braced = subject.charAt(0) == '[';
/* 1261 */         int colon = subject.indexOf(':');
/* 1262 */         if (colon > (braced ? 1 : 0))
/*      */         {
/* 1264 */           String prefix = subject.substring(braced ? 1 : 0, colon + 1);
/* 1265 */           boolean matched = true;
/* 1266 */           if (!SYSTEM_PREFIXES.contains(prefix.toLowerCase()))
/*      */           {
/* 1268 */             int paren = -1;
/* 1269 */             for (int i = 0; (matched) && (i < prefix.length() - 1); i++) {
/* 1270 */               char c = prefix.charAt(i);
/* 1271 */               if (((c == '(') || (c == '[')) && (i > 0) && (paren == -1)) {
/* 1272 */                 paren = i;
/* 1273 */               } else if (((c == ')') || (c == ']')) && (paren != -1)) {
/* 1274 */                 matched &= ((i > paren + 1) && (i == prefix.length() - 2));
/* 1275 */               } else if (!Character.isLetter(c)) {
/* 1276 */                 matched &= ((c >= '0') && (c <= '9') && (paren != -1));
/* 1277 */               } else if ((i >= 3) || (paren != -1)) {
/* 1278 */                 matched = false;
/*      */               }
/*      */             }
/*      */           }
/* 1282 */           if (matched) {
/* 1283 */             if ((braced) && (subject.endsWith("]"))) {
/* 1284 */               subject = subject.substring(colon + 1, subject.length() - 1);
/*      */             } else {
/* 1286 */               subject = subject.substring(colon + 1);
/*      */             }
/* 1288 */             trimmed = true;
/* 1289 */             continue;
/*      */           }
/*      */         }
/*      */         
/*      */ 
/* 1294 */         if (!LC.conversation_ignore_maillist_prefix.booleanValue()) break;
/*      */         int bclose;
/* 1296 */         if ((!braced) || ((bclose = subject.indexOf(']')) <= 0) || (subject.lastIndexOf('[', bclose) != 0)) break;
/* 1297 */         String remainder = subject.substring(bclose + 1).trim();
/* 1298 */         if (remainder.length() <= 0) break;
/* 1299 */         subject = remainder;
/*      */       }
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 1305 */     return new Pair(subject, Boolean.valueOf(trimmed));
/*      */   }
/*      */   
/*      */   @VisibleForTesting
/*      */   static String compressWhitespace(String value)
/*      */   {
/* 1311 */     if (Strings.isNullOrEmpty(value)) {
/* 1312 */       return value;
/*      */     }
/* 1314 */     StringBuilder sb = new StringBuilder();
/* 1315 */     int i = 0;int len = value.length(); for (int last = -1; i < len; i++) {
/* 1316 */       char c = value.charAt(i);
/* 1317 */       if (c <= ' ') {
/* 1318 */         c = ' ';
/* 1319 */         if (c == last) {}
/*      */       }
/*      */       else
/*      */       {
/* 1323 */         sb.append((char)(last = c));
/*      */       } }
/* 1325 */     return sb.toString();
/*      */   }
/*      */   
/*      */   private void normalizeSubject() {
/* 1329 */     if (this.normalizedSubject != null) {
/* 1330 */       return;
/*      */     }
/*      */     try {
/* 1333 */       this.normalizedSubject = (this.subject = StringUtil.stripControlCharacters(Mime.getSubject(getMimeMessage())));
/*      */     }
/*      */     catch (MessagingException e) {}
/*      */     
/* 1337 */     if (this.subject == null) {
/* 1338 */       this.normalizedSubject = (this.subject = "");
/* 1339 */       this.subjectIsReply = false;
/*      */     } else {
/* 1341 */       Pair<String, Boolean> normalized = trimPrefixes(this.subject);
/* 1342 */       this.normalizedSubject = compressWhitespace((String)normalized.getFirst());
/* 1343 */       this.subjectIsReply = ((Boolean)normalized.getSecond()).booleanValue();
/* 1344 */       this.normalizedSubject = DbMailItem.normalize(this.normalizedSubject, 1024);
/*      */     }
/*      */   }
/*      */   
/*      */   public static String normalize(String subject) {
/* 1349 */     String trimmed = compressWhitespace((String)trimPrefixes(StringUtil.stripControlCharacters(subject)).getFirst());
/* 1350 */     return DbMailItem.normalize(trimmed, 1024);
/*      */   }
/*      */   
/*      */   public static boolean isReply(String subject) {
/* 1354 */     return ((Boolean)trimPrefixes(subject).getSecond()).booleanValue();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public Threader getThreader(Mailbox mbox)
/*      */     throws ServiceException
/*      */   {
/* 1362 */     Threader threader = (Threader)this.threaders.get(mbox);
/* 1363 */     if (threader == null) {
/* 1364 */       threader = new Threader(mbox, this);
/* 1365 */       this.threaders.put(mbox, threader);
/*      */     }
/* 1367 */     return threader;
/*      */   }
/*      */   
/*      */   public static class CalendarPartInfo
/*      */   {
/*      */     public ZCalendar.ZVCalendar cal;
/*      */     public ZCalendar.ICalTok method;
/*      */     public boolean wasForwarded;
/*      */   }
/*      */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/mime/ParsedMessage.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */